﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using DicomDemo;
using DICOMViewer.Config;
using Leadtools.Demos;
using Leadtools.Dicom;
using Leadtools.DicomDemos;
using Leadtools.DicomDemos.Scu.CFind;
using Main3DDemo;

namespace DICOMViewer
{
    public partial class MainForm : Form
    {
        public delegate void AddSeriesItemDelegate(DicomDataSet ds);

        private CFind cfind;
        private readonly string AETitle = "Client1";
        private string patientId;
        private readonly int Port = 1000;

        private Queue<string> queue = new Queue<string>();
        private string seriesInstance;
        private readonly DicomServer server;
        private string studyInstance;
        private string workPath;
        private Thread th;
        private int width;
        private int height;

        public MainForm()
        {
            InitializeComponent();
            this.SizeChanged += MainForm_SizeChanged;
            FormClosing += MainForm_FormClosing;
            cfind = new CFind
            {
                ImplementationClass = ConstDefineValues.CONFIGURATION_IMPLEMENTATIONCLASS,
                ProtocolVersion = ConstDefineValues.CONFIGURATION_PROTOCOLVERSION,
                ImplementationVersionName = ConstDefineValues.CONFIGURATION_IMPLEMENTATIONVERSIONNAME
            };
            cfind.Status += cfind_Status;
            cfind.FindComplete += cfind_FindComplete;
            cfind.MoveComplete += cfind_MoveComplete;

            server = new DicomServer
            {
                AETitle = "LEAD_SERVER",
                Address = IPAddress.Parse(Convert.ToString("192.168.3.29")),
                Port = 104,
                Timeout = 30,
                IpType = DicomNetIpTypeFlags.Ipv4
            };
        }

        private void MainForm_SizeChanged(object sender, EventArgs e)
        {
            int changedWidth = this.Width - width;
            int changedHight = this.Height - height;
            this.panel1.Height = this.panel1.Height + changedHight;
            this.mainPanel.Width = this.mainPanel.Width + changedWidth;
            width = Width;
            height = Height;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            width = Width;
            height = Height;
            //发送查询study的命令，目前先写在这里，方便调试
            CFindQuery dcmQuery = new CFindQuery();
            cfind.Find(server, FindType.Study, dcmQuery, AETitle);
            mainPanel.seriesBrowserDialog.DicomDirAdded += mainPanel_DicomDirAdded;
        }
        /// <summary>
        /// DicomDir读取完毕之后的事件，主要用于构成seriesListView的内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mainPanel_DicomDirAdded(object sender, EventArgs e)
        {
            StudyBrowserDataSet seriesDs =  mainPanel.seriesBrowserDialog.seriesDataSet;
            
        }

        private void cfind_Status(object sender, StatusEventArgs e)
        {
            var message = "Unknown Error";
            var action = "";
            var done = false;

            if (e.Type == StatusType.Error)
            {
                action = "Error";
                message = "Error occurred.\r\n";
                message += "\tError code is:\t" + e.Error;
            }
            else
            {
                switch (e.Type)
                {
                    case StatusType.ConnectFailed:
                        action = "Connect";
                        message = "Operation failed.";
                        done = true;
                        break;
                    case StatusType.ConnectSucceeded:
                        action = "Connect";
                        message = "Operation succeeded.\r\n";
                        message += "\tPeer Address:\t" + e.PeerIP + "\r\n";
                        message += "\tPeer Port:\t\t" + e.PeerPort;
                        break;
                    case StatusType.SendAssociateRequest:
                        action = "Associate Request";
                        message = "Request sent.";
                        break;
                    case StatusType.ReceiveAssociateAccept:
                        action = "Associcated Accept";
                        message = "Received.\r\n";
                        message += "\tCalling AE:\t" + e.CallingAE + "\r\n";
                        message += "\tCalled AE:\t" + e.CalledAE;
                        break;
                    case StatusType.ReceiveAssociateRequest:
                        action = "Associcated Request";
                        message = "Received.\r\n";
                        message += "\tCalling AE:\t" + e.CallingAE + "\r\n";
                        message += "\tCalled AE:\t" + e.CalledAE;
                        break;
                    case StatusType.ReceiveAssociateReject:
                        action = "Associate Reject";
                        message = "Received Associate Reject!";
                        message += "\r\n\tSource: " + e.Source;
                        message += "\r\n\tResult: " + e.Result;
                        message += "\r\n\tReason: " + e.Reason;
                        done = true;
                        break;
                    case StatusType.AbstractSyntaxNotSupported:
                        action = "Error";
                        message = "Abstract Syntax NOT supported!";
                        done = true;
                        break;
                    case StatusType.SendCFindRequest:
                        action = "C-FIND";
                        message = "Sending request";
                        break;
                    case StatusType.ReceiveCFindResponse:
                        action = "C-FIND";
                        if (e.Error == DicomExceptionCode.Success)
                        {
                            message = "Operation completed successfully.";
                        }
                        else
                        {
                            if (e.Status == DicomCommandStatusType.Pending)
                            {
                                message = "Additional operations pending.";
                            }
                            else
                            {
                                message = "Error in response Status code is: " + e.Status;
                            }
                        }
                        break;
                    case StatusType.ConnectionClosed:
                        action = "Connect";
                        message = "Network Connection closed!";
                        done = true;
                        break;
                    case StatusType.ProcessTerminated:
                        action = "";
                        message = "Process has been terminated!";
                        done = true;
                        break;
                    case StatusType.SendReleaseRequest:
                        action = "Release Request";
                        message = "Request sent.";
                        break;
                    case StatusType.ReceiveReleaseResponse:
                        action = "Release Response";
                        message = "Response received.";
                        done = true;
                        break;
                    case StatusType.SendCMoveRequest:
                        action = "C-MOVE";
                        message = "Sending request";
                        break;
                    case StatusType.ReceiveCMoveResponse:
                        action = "C-MOVE";
                        message = "Received response\r\n";
                        message += "\tStatus: " + e.Status + "\r\n";
                        message += "\tNumber Completed: " + e.NumberCompleted + "\r\n";
                        message += "\tNumber Remaining: " + e.NumberRemaining;
                        break;
                    case StatusType.SendCStoreResponse:
                        action = "C-STORE";
                        message = "Sending response";
                        break;
                    case StatusType.ReceiveCStoreRequest:
                        action = "C-STORE";
                        message = "Received request";
                        break;
                    case StatusType.Timeout:
                        message = "Communication timeout. Process will be terminated.";
                        done = true;
                        break;
                }
            }
        }

        private CounterDialog counter;

        private void cfind_FindComplete(object sender, FindCompleteEventArgs e)
        {
            switch (e.Type)
            {
                case FindType.Study:
                    StartUpdate(listViewStudies);
                    foreach (DicomDataSet ds in e.Datasets)
                    {
                        AddStudyItem(ds);
                    }
                    EndUpdate(listViewStudies);
                    break;
                case FindType.StudySeries:
                    //创建保存图片的文件夹
                    Directory.CreateDirectory(workPath);
                    int SeriesInstancenumber = 0;
                    foreach (DicomDataSet ds in e.Datasets)
                    {
                        var SeriesInstanceUID = Utils.GetStringValue(ds, DemoDicomTags.SeriesInstanceUID);
                         SeriesInstancenumber +=int.Parse(Utils.GetStringValue(ds, DemoDicomTags.NumberOfSeriesRelatedInstances)) ;
                        queue.Enqueue(SeriesInstanceUID);
                    }
                    if (th == null || (th != null && !th.IsAlive))
                    {
                        //启动新线程并异步发送获取Series请求！
                        th = new Thread(() =>
                        {
                            //将线程归到cfind的workthread结束之后运行
                            cfind.workThread.Join();
                            //考虑到一直只有一个线程访问queue，这里不加锁了
                            if (queue.Count <= 0) return;
                            this.Invoke(new EventHandler(delegate
                            {
                                counter = new CounterDialog(SeriesInstancenumber, 1, this, "aaa", "bbb");
                                counter.Show();
                            }));
                            SendMoveSeriesCmd();
                        });
                    }
                    th.Start();
                    break;
            }
        }

        private void cfind_MoveComplete(object sender, MoveCompleteEventArgs e)
        {
            for (var i = 0; i < e.Datasets.Count; i++)
            {
                DicomDataSet ds = e.Datasets[i];
                //按照jpeg2000格式压缩图像
                Utility.ImageConverter.ConvertJpeg2000(ds);
                //将DataSet保存为dcm文件
                ds.Save(workPath + "\\" + i + ".dcm",
                    DicomDataSetSaveFlags.None);
                ds.Dispose();
                this.counter.Invoke(new EventHandler(delegate
                {
                    counter.Percent++;
                }));
            }
            this.Invoke(new EventHandler(delegate { counter.Percent++; }));
            //获取完成！
            if (queue.Count <= 0)
            {
                this.counter.Invoke(new EventHandler(delegate
                {
                    if (counter != null)
                    {
                        counter.Close();
                        counter.Dispose();
                        counter = null;
                    }
                }));
                //调用函数构建DicomDir
                Utility.DicomDirMaker.CreateDicomDirectory(workPath);
                //通过Invoke控件Tabcontrol来驱动3DViewer读取数据
                this.tabControl1.Invoke(new EventHandler(delegate
                {
                    this.tabControl1.SelectedTab = this.tabPage2;
                    //直接调用mainPanel中seriesBrowserDialog窗口的相关方法，窗口已被隐藏
                    mainPanel.seriesBrowserDialog.AddDicomDirectory(workPath + "\\DICOMDIR");
                    mainPanel.seriesBrowserDialog.InitializeBackgroundWorker(false);
                }));
                return;
            }
            //获取尚未完成！继续异步排队！
            if (th == null || (th != null && !th.IsAlive))
            {
                th = new Thread(() =>
                {
                    Console.Out.WriteLine("th start!");
                    cfind.workThread.Join();
                    if (queue.Count > 0)
                    {
                        Console.Out.WriteLine("send move!");
                        SendMoveSeriesCmd();
                    }
                });
            }
            th.Start();
        }

        private void SendMoveSeriesCmd()
        {
            if (queue.Count <= 0) return;
            seriesInstance = queue.Dequeue();
            cfind.MoveSeries(server, AETitle, patientId, studyInstance, seriesInstance, Port);
        }

        #region 窗口关闭相关

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            //            Application.Exit();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (cfind != null)
            {
                cfind.Terminate();
                cfind.CloseForced(true);
            }
        }

        #endregion

        private void AddSeriesItem(DicomDataSet ds)
        {
            if (InvokeRequired)
            {
                Invoke(new AddSeriesItemDelegate(AddSeriesItem), ds);
            }
            else
            {
                ListViewItem item = new ListViewItem();
                item.ImageIndex = listViewSeries.Items.Count;
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("序列码：{0}", Utils.GetStringValue(ds, DemoDicomTags.SeriesNumber));

                sb.AppendLine();
                sb.AppendFormat("检查类型：", Utils.GetStringValue(ds, DemoDicomTags.Modality));
                sb.AppendLine();
                sb.AppendFormat("相关实例数量：", Utils.GetStringValue(ds, DemoDicomTags.NumberOfSeriesRelatedInstances));
                item.Text = sb.ToString();
                item.Tag = Utils.GetStringValue(ds, DemoDicomTags.SeriesInstanceUID);
                listViewSeries.Items.Add(item);
            }
        }

        /// <summary>
        /// studies列表双击事件，触发获取Study相关所有Series下所有Image的操作！
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listViewStudies_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (listViewStudies.SelectedItems.Count == 0)
                return;
            patientId = listViewStudies.SelectedItems[0].SubItems[0].Text;
            studyInstance = listViewStudies.SelectedItems[0].Tag as string;
            if (!string.IsNullOrEmpty(studyInstance))
            {
                //创建存放dcm文件的文件夹
                workPath = Application.StartupPath + "\\dicomfile\\" + studyInstance;
                if (Directory.Exists(workPath))
                {
                    DialogResult result = MessageBox.Show("当前Study相关文件已存在，选Yes重新下载，选No直接读取文件。", "注意", MessageBoxButtons.YesNo);
                    if (result == DialogResult.No)
                    {
                        //通过Invoke控件Tabcontrol来驱动3DViewer读取数据
                        this.tabControl1.Invoke(new EventHandler(delegate
                        {
                            this.tabControl1.SelectedTab = this.tabPage2;
                            //直接调用mainPanel中seriesBrowserDialog窗口的相关方法，窗口已被隐藏
                            //清除原有数据和状态
                            mainPanel.seriesBrowserDialog.btnClear_Click(null, null);
                            //读取目录
                            mainPanel.seriesBrowserDialog.AddDicomDirectory(workPath + "\\DICOMDIR");
                            //读取Image
                            mainPanel.seriesBrowserDialog.InitializeBackgroundWorker(false);
                        }));
                        return;
                    }
                }
                CFindQuery query = new CFindQuery();
                query.StudyInstanceUid = studyInstance;
                query.PatientID = listViewStudies.SelectedItems[0].SubItems[0].Text;
                cfind.Find(server, FindType.StudySeries, query, AETitle);
            }

            //Cursor = Cursors.WaitCursor;
        }

        #region StudyListView相关方法

        public delegate void StartUpdateDelegate(ListView lv);

        private void StartUpdate(ListView lv)
        {
            if (InvokeRequired)
            {
                Invoke(new StartUpdateDelegate(StartUpdate), lv);
            }
            else
            {
                lv.Items.Clear();
                lv.BeginUpdate();
            }
        }

        public delegate void EndUpdateDelegate(ListView lv);

        private void EndUpdate(ListView lv)
        {
            if (InvokeRequired)
            {
                Invoke(new EndUpdateDelegate(EndUpdate), lv);
            }
            else
            {
                lv.EndUpdate();
            }
        }

        public delegate void AddStudyItemDelegate(DicomDataSet ds);

        private void AddStudyItem(DicomDataSet ds)
        {
            ListViewItem item;
            string tagValue;

            if (InvokeRequired)
            {
                Invoke(new AddStudyItemDelegate(AddStudyItem), ds);
            }
            else
            {
                tagValue = Utils.GetStringValue(ds, DemoDicomTags.PatientID);
                item = listViewStudies.Items.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.AccessionNumber);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.PatientName);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.PatientSex);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.PatientBirthDate);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.StudyDate);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.ReferringPhysicianName);
                item.SubItems.Add(tagValue);

                tagValue = Utils.GetStringValue(ds, DemoDicomTags.StudyDescription);
                item.SubItems.Add(tagValue);

                item.Tag = Utils.GetStringValue(ds, DemoDicomTags.StudyInstanceUID);
            }
        }

        #endregion

        private void button1_Click(object sender, EventArgs e)
        {
            //string path = "D:\\MyWork\\DicomViewer\\DicomViewer\\DICOMViewer\\bin\\Debug\\dicomfile\\1.2.86.76547135.7.257392.20171024095543\\DICOMDIR";
        }
    }
}